#pragma once
#include <Rz/Object.h>
#include <Rz/IEquatable.h>
#include <Rz/IHumanReadable.h>
#include <Rz/Collections/InitializerList.h>

RZ_CLASS_FWD_DECL3(Rz, Graphics, Math, Vector3);

namespace Rz { namespace Graphics { namespace Math {

class Vector4 :
	public Object,
	public IEquatable<Vector4>,
	public IHumanReadable
{
	public:
		RZ_RTTI(Rz::Graphics, Vector4);
		RZ_RTTI_IMPLEMENTS(Object, IEquatable<Vector4>, IHumanReadable);
		RZ_RTTI_END;

		union
		{
			struct { f32 X, Y, Z, W; };
			struct { f32 Cell[4]; };
		};

		Vector4(std::initializer_list<f32> v);
		Vector4();
		Vector4(f32 x, f32 y, f32 z, f32 w);
		Vector4(const f32* ptr);
		Vector4(const Vector3& vec);
		Vector4(const Vector4& vec);

		void Set(f32 x, f32 y, f32 z, f32 w);
		f32 Length() const;
		void Normalize();

		Vector4 Normalized() const;

		static f32 Distance(const Vector4& u, const Vector4& v);
		static f32 Dot(const Vector4& u, const Vector4& v);


		f32 operator [] (s32 index) const;
		f32& operator [] (s32 index);

		Vector4 operator + (const Vector4& vec) const;
		Vector4 operator - (const Vector4& vec) const;
		Vector4 operator * (const Vector4& vec) const;
		Vector4 operator / (const Vector4& vec) const;
		Vector4 operator + (f32 v) const;
		Vector4 operator - (f32 v) const;
		Vector4 operator * (f32 v) const;
		Vector4 operator / (f32 v) const;

		Vector4& operator += (const Vector4& v);
		Vector4& operator -= (const Vector4& v);
		Vector4& operator *= (const Vector4& v);
		Vector4& operator /= (const Vector4& v);
		Vector4& operator += (f32 v);
		Vector4& operator -= (f32 v);
		Vector4& operator *= (f32 v);
		Vector4& operator /= (f32 v);
		Vector4 operator - () const;

		friend Vector4 operator + (f32 v, const Vector4& u);
		friend Vector4 operator - (f32 v, const Vector4& u);
		friend Vector4 operator * (f32 v, const Vector4& u);
		friend Vector4 operator / (f32 v, const Vector4& u);

		// IHumanReadable
		virtual String ToString() const override;

		// IEquatable
		bool Equals(const Vector4& r) const override;

		bool operator == (const Vector4& r) const override;
		bool operator != (const Vector4& r) const override;

		static const Vector4 Zero;
		static const Vector4 One;
		static const Vector4 NormalX;
		static const Vector4 NormalY;
		static const Vector4 NormalZ;
		static const Vector4 NormalW;
};

} } }
